﻿Imports System.Text
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Data
Imports System.Windows.Documents
Imports System.Windows.Input
Imports System.Windows.Media
Imports System.Windows.Media.Imaging
Imports System.Windows.Navigation
Imports System.Windows.Shapes
Imports System.Text.RegularExpressions
Imports System.ComponentModel
Imports System.Diagnostics.CodeAnalysis
Imports Microsoft.VisualStudio.Text.Editor
Imports Microsoft.VisualStudio.Text

Namespace Microsoft.VisualStudio.RegularExpression.UI
    Partial Public Class RegexEditorDialog
        Inherits Window
        Private WithEvents textViewEventManager As TextViewEventManager
        Private context As RegexDataContext
        Private regexEditor As IWpfTextViewHost

        ''' <summary>
        ''' 
        ''' </summary>
        Public Sub New(ByVal regexEditor As IWpfTextViewHost)
            InitializeComponent()

            Me.regexEditor = regexEditor
            textViewEventManager = Me.regexEditor.TextView.Properties.GetProperty(Of TextViewEventManager)(textViewEventManager.Key)

            context = New RegexDataContext
            context.RegexRepositoryService = New RegexRepositoryService
            context.SelectedItem = context.RegexRepositoryService.CreateItem("[new]", String.Empty)

            Me.expressionContainer.Children.Add(regexEditor.HostControl)

            Me.DataContext = context

            Me.regexEditor.TextView.Caret.MoveTo(New SnapshotPoint(Me.regexEditor.TextView.TextBuffer.CurrentSnapshot, Me.regexEditor.TextView.TextBuffer.CurrentSnapshot.Length))
            Me.regexEditor.HostControl.Focus()
        End Sub

        Private Sub OnIntellisenseSessionStart() Handles textViewEventManager.IntellisenseSessionStart
            DisableCancelAndDefaultButtons()
        End Sub

        Private Sub OnIntellisenseSessionEnd() Handles textViewEventManager.IntellisenseSessionEnd
            EnableCancelAndDefaultButtons()
        End Sub

        Friend Overloads Shared Function ShowDialog(ByVal regex As String, ByVal regexEditor As IWpfTextViewHost, <System.Runtime.InteropServices.Out()> ByRef result As String) As Boolean?
            Dim editorDialog As New RegexEditorDialog(regexEditor)
            Dim selectedRepositoryItem = editorDialog.context.RegexRepositoryService.Items.FirstOrDefault(Function(item) String.Compare(item.Regex, regex, True) = 0)

            If selectedRepositoryItem IsNot Nothing Then
                editorDialog.context.SelectedItem = selectedRepositoryItem
                editorDialog.regexRepositoryItemsDataGrid.SelectedItem = selectedRepositoryItem
            Else
                editorDialog.context.SelectedItem.Regex = regex
            End If

            Dim dialogResult? = editorDialog.ShowDialog()
            result = editorDialog.GetExpressionText()

            Return dialogResult
        End Function

        Friend Sub EnableCancelAndDefaultButtons()
            Me.buttonCancel.IsCancel = True
            Me.buttonAccept.IsDefault = Me.buttonCancel.IsCancel
        End Sub

        Friend Sub DisableCancelAndDefaultButtons()
            Me.buttonCancel.IsCancel = False
            Me.buttonAccept.IsDefault = Me.buttonCancel.IsCancel
        End Sub

        Private Sub Expander_Expanded(ByVal sender As Object, ByVal e As RoutedEventArgs)
            Me.MaxHeight = 580
            Me.MinHeight = Me.MaxHeight
            Me.Height = Me.MinHeight
        End Sub

        Private Sub Expander_Collapsed(ByVal sender As Object, ByVal e As RoutedEventArgs)
            Me.MaxHeight = 230
            Me.MinHeight = Me.MaxHeight
            Me.Height = Me.MinHeight
        End Sub

        Private Function GetExpressionText() As String
            Return Me.regexEditor.TextView.TextBuffer.CurrentSnapshot.GetText()
        End Function

        <SuppressMessage("Microsoft.Design", "CA1031")>
        Private Sub ButtonMatch_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
            Me.treeViewResult.Items.Clear()

            Dim regex As Regex = Nothing
            Try
                regex = New Regex(GetExpressionText(), RegexOptions.Multiline)
            Catch ex As Exception
                Me.treeViewResult.Items.Add(New TreeViewItem With {.Header = ex.Message, .IsExpanded = True})
                Return
            End Try


            Dim matches = regex.Matches(Me.textBoxMatches.Text)

            If matches.Count > 0 Then
                For Each match As Match In matches
                    If match.Success Then
                        Dim matchTreeItem As New TreeViewItem With {.Header = NormalizeMatchValue(match.Value), .IsExpanded = True, .Tag = match}
                        Me.treeViewResult.Items.Add(matchTreeItem)

                        For i = 1 To match.Groups.Count - 1
                            Dim groupName = regex.GroupNameFromNumber(i)

                            matchTreeItem.Items.Add(New TreeViewItem With {.Header = String.Format("{0}: '{1}'", groupName, NormalizeMatchValue(match.Groups(i).Value)), .Tag = match.Groups(i)})
                        Next i
                    End If
                Next match
            Else
                Me.treeViewResult.Items.Add(New TreeViewItem With {.Header = "No results"})
            End If
        End Sub

        Private Function NormalizeMatchValue(ByVal value As String) As String
            Return value.Replace(Environment.NewLine, String.Empty)
        End Function

        <SuppressMessage("Microsoft.Design", "CA1031")>
        Private Sub ButtonAccept_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
            Try
                If Me.context.SelectedItem IsNot Nothing Then
                    Me.context.SelectedItem.Regex = GetExpressionText()
                    Me.context.RegexRepositoryService.Save(Me.context.SelectedItem)
                End If
            Catch ex As Exception
                MessageBox.Show(String.Format("The repository could not be saved. Error: '{0}'", ex.Message))
            End Try

            DialogResult = True
            Me.Close()
        End Sub

        Private Sub RegexRepositoryItemsDataGrid_SelectionChanged(ByVal sender As Object, ByVal e As SelectionChangedEventArgs)
            Me.context.SelectedItem = TryCast(Me.regexRepositoryItemsDataGrid.SelectedItem, RegexRepositoryItem)

            If Me.context.SelectedItem IsNot Nothing Then
                Me.regexEditor.TextView.TextBuffer.Replace(New Microsoft.VisualStudio.Text.Span(0, Me.regexEditor.TextView.TextBuffer.CurrentSnapshot.Length), Me.context.SelectedItem.Regex)
            End If

            Me.treeViewResult.Items.Clear()

            Me.menuItemDuplicateRepositoryItem.IsEnabled = Me.context.SelectedItem IsNot Nothing
            Me.menuItemDeleteRepositoryItem.IsEnabled = Me.menuItemDuplicateRepositoryItem.IsEnabled
        End Sub

        Private Sub MenuItemDeleteRepositoryItem_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
            If Me.regexRepositoryItemsDataGrid.SelectedItems IsNot Nothing Then
                For Each selectedItem As RegexRepositoryItem In Me.regexRepositoryItemsDataGrid.SelectedItems.Cast(Of RegexRepositoryItem)().ToList()
                    Me.context.RegexRepositoryService.Delete(selectedItem)
                Next selectedItem
            End If
        End Sub

        Private Class RegexDataContext
            Implements INotifyPropertyChanged
            Public Property RegexRepositoryService As RegexRepositoryService

            Private mSelectedItem As RegexRepositoryItem
            Public Property SelectedItem As RegexRepositoryItem
                Get
                    Return Me.mSelectedItem
                End Get
                Set(ByVal value As RegexRepositoryItem)
                    Me.mSelectedItem = value
                    OnPropertyChanged("SelectedItem")
                End Set
            End Property

            Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged

            Protected Overridable Sub OnPropertyChanged(ByVal propertyName As String)
                If Me.PropertyChangedEvent IsNot Nothing Then
                    RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
                End If
            End Sub
        End Class

        Private Sub MenuItemDuplicateRepositoryItem_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
            If Me.regexRepositoryItemsDataGrid.SelectedItems IsNot Nothing Then
                For Each selectedItem As RegexRepositoryItem In Me.regexRepositoryItemsDataGrid.SelectedItems.Cast(Of RegexRepositoryItem)().ToList()
                    Dim item = TryCast(selectedItem.Clone(), RegexRepositoryItem)
                    Me.context.RegexRepositoryService.GenerateUniqueTitle(item)

                    Me.context.RegexRepositoryService.Save(item)
                    Me.regexRepositoryItemsDataGrid.SelectedItem = item
                Next selectedItem
            End If
        End Sub

        Private Sub ButtonCancel_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
            Me.Close()
        End Sub

        Private Sub TreeViewResult_SelectedItemChanged(ByVal sender As Object, ByVal e As RoutedPropertyChangedEventArgs(Of Object))
            Dim selectedItem = TryCast(e.NewValue, TreeViewItem)
            If selectedItem IsNot Nothing Then
                Dim capture = TryCast(selectedItem.Tag, Capture)
                If capture IsNot Nothing Then
                    Me.textBoxMatches.Focus()
                    Me.textBoxMatches.Select(capture.Index, capture.Length)
                    Me.textBoxMatchesShouldKeepFocus = True
                    selectedItem.Focus()
                End If
            End If
        End Sub

        Private textBoxMatchesShouldKeepFocus As Boolean

        Private Sub TextBoxMatches_LostFocus(ByVal sender As Object, ByVal e As RoutedEventArgs)
            If textBoxMatchesShouldKeepFocus Then
                textBoxMatchesShouldKeepFocus = False
                e.Handled = True
            End If
        End Sub

        Private Sub textBoxFilter_TextChanged(ByVal sender As Object, ByVal e As TextChangedEventArgs)
            context.RegexRepositoryService.Filter = textBoxFilter.Text
            e.Handled = True
        End Sub
    End Class
End Namespace